#include "input.h"
#include "textrenderer.h"
#include "OgreStringConverter.h"
#include <iostream>

using namespace std;

InputHandler* InputHandler::singleton = 0;


InputHandler::InputHandler(Ogre::RenderWindow *window)
{
	unsigned long hWnd;
	OIS::ParamList pl;
	std::ostringstream windowHndStr;

	window->getCustomAttribute("WINDOW", &hWnd);
	windowHndStr << hWnd;
	pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

#if defined OIS_LINUX_PLATFORM
	pl.insert(std::make_pair(std::string("x11_mouse_grab"), std::string("false")));
	pl.insert(std::make_pair(std::string("x11_mouse_hide"), std::string("false")));
	pl.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("false")));
	pl.insert(std::make_pair(std::string("XAutoRepeatOn"), std::string("false")));
#endif

	m_ois = OIS::InputManager::createInputSystem(pl);

	mMouse = static_cast<OIS::Mouse*>(m_ois->createInputObject( OIS::OISMouse, true ));
	mKeyboard = static_cast<OIS::Keyboard*>(m_ois->createInputObject( OIS::OISKeyboard, true ));
	try {
		mJoy = static_cast<OIS::JoyStick*>(m_ois->createInputObject( OIS::OISJoyStick, true ));
		mJoy->setEventCallback(this);
	}
	catch(...) {
		mJoy = 0;
	}

	mMouse->setEventCallback(this);
	mKeyboard->setEventCallback(this);
	
	modeAutomatic = true;
	modePowerSteering = false;
	modeParking = false;
	modeArcade = false;
	singleton = this;
	
	TextRenderer::getSingleton().addTextBox("keyboard_modes", "", 10, 10, 100, 20, Ogre::ColourValue::Green);
	updateScreener();
}

InputHandler::~InputHandler() {
	if (mMouse)
		m_ois->destroyInputObject(mMouse);
	if (mKeyboard)
		m_ois->destroyInputObject(mKeyboard);
	if (mJoy)
		m_ois->destroyInputObject(mJoy);

	OIS::InputManager::destroyInputSystem(m_ois);
}

InputHandler* InputHandler::getSingleton()
{
	return singleton;
}

void InputHandler::updateScreener()
{
	ostringstream ostream;
	
	ostream << "Modes: ";
	
	if(modeAutomatic)
		ostream << "Automatic gyro";
	else
		ostream << "Manual gyro";
	if(modePowerSteering)
		ostream << ", Power Steering";
	if(modeParking)
		ostream << ", Parking";
	if(modeArcade)
		ostream << ", Arcade";
	
	TextRenderer::getSingleton().setText("keyboard_modes", ostream.str());
}

void InputHandler::capture() {
	if(mMouse)
		mMouse->capture();
	
	if(mKeyboard)
		mKeyboard->capture();
	
	if(mJoy)
		mJoy->capture();
}

const vector<Action> InputHandler::getCurrentEvents()
{
	return currentEvents;
}

void  InputHandler::setWindowExtents(int width, int height)
{
	//Set Mouse Region.. if window resizes, we should alter this to reflect as well
	const OIS::MouseState &ms = mMouse->getMouseState();
	ms.width = width;
	ms.height = height;
}

// MouseListener
bool InputHandler::mouseMoved(const OIS::MouseEvent &evt) {
	return true;
}

bool InputHandler::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) {
	return true;
}

bool InputHandler::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) {
	return true;
}

bool InputHandler::setMode(const Action& action, bool keyReleased) {
	bool ret = false;
	
	if(!keyReleased)
		switch(action)
		{
			case ACTION_MODE_AUTOMATIC:
				modeAutomatic = !modeAutomatic;
				ret = true;
				break;
			case ACTION_MODE_POWER_STEERING:
				modePowerSteering = !modePowerSteering;
				ret = true;
				break;
			case ACTION_MODE_PARKING:
				modeParking = !modeParking;
				ret = true;
				break;
			case ACTION_MODE_ARCADE:
				modeArcade = !modeArcade;
				ret = true;
				break;
		}
	
	switch(action)
	{
		case FAST_ACTION_MODE_AUTOMATIC:
			modeAutomatic = !modeAutomatic;
			ret = true;
			break;
		case FAST_ACTION_MODE_POWER_STEERING:
			modePowerSteering = !modePowerSteering;
			ret = true;
			break;
		case FAST_ACTION_MODE_PARKING:
			modeParking = !modeParking;
			ret = true;
			break;
		case FAST_ACTION_MODE_ARCADE:
			modeArcade = !modeArcade;
			ret = true;
			break;
	}
	
	return ret;
}

bool InputHandler::getModeAutomatic(){
	return modeAutomatic;
}
	
bool InputHandler::getModeArcade(){
	return modeArcade;
}

bool InputHandler::getModePowerSteering(){
	return modePowerSteering;
}

bool InputHandler::getModeParking(){
	return modeParking;
}

// KeyListener
bool InputHandler::keyPressed(const OIS::KeyEvent &evt) {
	Action action = actionMap.getAction(evt, getModeParking());
	
	if(!setMode(action)) {
		currentEvents.push_back(action);
	} else {
		updateScreener();
	}
	
	return true;
}

bool InputHandler::keyReleased(const OIS::KeyEvent &evt) {
	Action action = actionMap.getAction(evt, getModeParking());
	
	if(setMode(action, true)) {
		updateScreener();
		return true;
	}
	vector<Action>::iterator tmp = find(currentEvents.begin(), currentEvents.end(), action);
	if(tmp != currentEvents.end())
		currentEvents.erase(tmp);
	
	return true;
}


// JoyStickListener
bool InputHandler::buttonPressed(const OIS::JoyStickEvent &evt, int index) {
	return true;
}

bool InputHandler::buttonReleased(const OIS::JoyStickEvent &evt, int index) {
	return true;
}

bool InputHandler::axisMoved(const OIS::JoyStickEvent &evt, int index) {
	return true;
}

bool InputHandler::povMoved(const OIS::JoyStickEvent &evt, int index) {
	return true;
}














ActionMap::ActionMap(string settingsFile)
{
	loadActionMap(settingsFile);
}

ActionMap::~ActionMap()
{
	
}

void ActionMap::loadActionMap(string settingsFile)
{
	if(settingsFile == "")
	{
		mMap[OIS::KC_ESCAPE] = ACTION_SHUTDOWN;
		mMap[OIS::KC_UP] = ACTION_PITCH_DOWN;
		mMap[OIS::KC_DOWN] = ACTION_PITCH_UP;
		mMap[OIS::KC_LEFT] = ACTION_TURN_LEFT;
		mMap[OIS::KC_RIGHT] = ACTION_TURN_RIGHT;
		mMap[OIS::KC_A] = ACTION_ROLL_LEFT;
		mMap[OIS::KC_D] = ACTION_ROLL_RIGHT;
		mMap[OIS::KC_W] = ACTION_GO_FORWARD;
		mMap[OIS::KC_S] = ACTION_GO_BACKWARD;
		mMap[OIS::KC_F1] = ACTION_MODE_AUTOMATIC;
		mMap[OIS::KC_F2] = ACTION_MODE_ARCADE;
		mMap[OIS::KC_F3] = ACTION_MODE_POWER_STEERING;
		mMap[OIS::KC_F4] = ACTION_MODE_PARKING;
		mMap[OIS::KC_1] = FAST_ACTION_MODE_AUTOMATIC;
		mMap[OIS::KC_2] = FAST_ACTION_MODE_ARCADE;
		mMap[OIS::KC_3] = FAST_ACTION_MODE_POWER_STEERING;
		mMap[OIS::KC_4] = FAST_ACTION_MODE_PARKING;
		mMapParking[OIS::KC_UP] = ACTION_GO_UP;
		mMapParking[OIS::KC_DOWN] = ACTION_GO_DOWN;
		mMapParking[OIS::KC_LEFT] = ACTION_GO_LEFT;
		mMapParking[OIS::KC_RIGHT] = ACTION_GO_RIGHT;
	}
}

void ActionMap::saveActionMap(string settingsFile)
{
	
}

Action ActionMap::getAction(const OIS::KeyEvent &evt, bool modeParking)
{
	Action ret = ACTION_NONE;
	
	if(modeParking && mMapParking.find(evt.key) != mMap.end())
		ret = mMapParking[evt.key];
	
	if(ret == ACTION_NONE && mMap.find(evt.key) != mMap.end())
		ret = mMap[evt.key];
	
	return ret;
}

void ActionMap::mapAction(OIS::KeyCode key, Action action)
{
	mMap[key] = action;
}

